// BeamVars Library for PCMod (SERVER)

Msg( "=== PCBeamVars Library 1 Loaded ===\n" )

PCBeam = {}
PCBeam.Storage = {}
PCBeam.CheckTimer = 5 -- Seconds
PCBeam.SendDistance = 1024 -- Source Units

function PCBeam:BeamVars( pc, ply )
	if (!self:ValidateEntity( pc )) then return false end
	if (!self:ValidatePlayer( ply )) then return false end
	local id = pc:EntIndex()
	if (!self.Storage[ id ]) then self.Storage[ id ] = {} end
	umsg.Start( "pcbeam", ply )
		umsg.Short( id )
		umsg.Short( table.Count( self.Storage[ id ] ) )
		for k, v in pairs( self.Storage[ id ] ) do
			umsg.String( k .. "#" .. tostring( v ) .. "#" .. type( v ) )
		end
	umsg.End()
end

function PCBeam:BeamVarsToAll( pc )
	if (!self:ValidateEntity( pc )) then return false end
	local id = pc:EntIndex()
	if (!self.Storage[ id ]) then self.Storage[ id ] = {} end
	umsg.Start( "pcbeam" )
		umsg.Short( id )
		umsg.Short( table.Count( self.Storage[ id ] ) )
		for k, v in pairs( self.Storage[ id ] ) do
			umsg.String( k .. "#" .. tostring( v ) .. "#" .. type( v ) )
		end
	umsg.End()
end

function PCBeam:SetValue( pc, tag, value )
	if (!self:ValidateEntity( pc )) then return false end
	local id = pc:EntIndex()
	if (!self.Storage[ id ]) then self.Storage[ id ] = {} end
	local old = self.Storage[ id ][ tag ]
	self.Storage[ id ][ tag ] = value
	self:InvalidateEntityVars( pc )
	self:RunFullCheck()
end

function PCBeam:InvalidateEntityVars( pc )
	if (!self:ValidateEntity( pc )) then return false end
	for _, ply in pairs( player.GetAll() ) do
		if (!ply.PCBeamed) then ply.PCBeamed = {} end
		ply.PCBeamed[ pc:EntIndex() ] = false
	end
end

function PCBeam:ResetEntity( pc )
	if (!self:ValidateEntity( pc )) then return false end
	local id = pc:EntIndex()
	self.Storage[ id ] = nil
end

function PCBeam:ValidateEntity( ent )
	if (!ent) then return false end
	if (!ent:IsValid()) then return false end
	return true
end

function PCBeam:ValidatePlayer( ent )
	if (!ent) then return false end
	if (!ent:IsValid()) then return false end
	if (!ent:IsPlayer()) then return false end
	return true
end

function PCBeam:RunFullCheck()
	for _, ply in pairs( player.GetAll() ) do
		if (!ply.PCBeamed) then ply.PCBeamed = {} end
		for id, _ in pairs( PCBeam.Storage ) do
			local ent = ents.GetByIndex( id )
			if (PCBeam:ValidateEntity( ent )) then
				if (!ply.PCBeamed[ id ]) then
					if ((ply:GetPos()-ent:GetPos()):Length() < PCBeam.SendDistance) then
						PCBeam:BeamVars( ent, ply )
					end
					ply.PCBeamed[ id ] = true
				end
			end
		end
	end
end

timer.Create( "PCBeam_Check", PCBeam.CheckTimer, 0, function() PCBeam:RunFullCheck(); end )